<?php
class Silk_Types extends Silk_Gateway
{

    protected $_dao_class = 'Silk_Dao_Type';

    protected $_model_class = 'Silk_Type';

    protected $_primary_key = 'type_id';

    public function presave(array $pData){
	if ($pData['version'] === null)
	    $pData['version'] = 1.0;
	return $pData;
    }

    public function postSave(array $pData){
	$type_id = $pData['type_id'];

	$permission_name = "Type {$type_id} Create";
	$permission_resource = "type.{$type_id}";
	$permission_privilege = PERMISSION_CREATE;
	$permission_roles = array("Administrator");

	Silk::CreatePermission(
	    $permission_name,
	    $permission_resource,
	    $permission_privilege,
	    $permission_roles
	);

	$permission_name = "Type {$type_id} Edit";
	$permission_resource = "type.{$type_id}";
	$permission_privilege = PERMISSION_EDIT;
	$permission_roles = array("Administrator");

	Silk::CreatePermission(
	    $permission_name,
	    $permission_resource,
	    $permission_privilege,
	    $permission_roles
	);

	$permission_name = "Type {$type_id} Delete";
	$permission_resource = "type.{$type_id}";
	$permission_privilege = PERMISSION_DELETE;
	$permission_roles = array("Administrator");

	Silk::CreatePermission(
	    $permission_name,
	    $permission_resource,
	    $permission_privilege,
	    $permission_roles
	);

	$permission_name = "Type {$type_id} View";
	$permission_resource = "type.{$type_id}";
	$permission_privilege = PERMISSION_VIEW;
	$permission_roles = array("Guest", "Administrator");

	Silk::CreatePermission(
	    $permission_name,
	    $permission_resource,
	    $permission_privilege,
	    $permission_roles
	);

	return $pData;
    }

    public function postDelete($pTypeId){
	$resource = "type.{$pTypeId}";
	$Permissions = new Silk_Permissions();
	$permissions = $Permissions->fetchByResource($resource);

	foreach ($permissions as $permission)
	    $permission->delete();
    }

    public function clearPermissionsForUser($pType, $pUser){
	$type_id = $this->getModelObjectId($pType);
	$resource = "type.{$type_id}";

	$Users = new Silk_Users();
	$user_id = $Users->getModelObjectId($pUser);

	$Permissions = new Silk_Permissions();
	$permissions = $Permissions->fetchByResource($resource);

	foreach ($permissions as $permission){
	    Doctrine_Query::create()
		->delete('Silk_Dao_UserPermission up')
		->where('up.user_id = ?', $user_id)
		->andWhere('up.permission_id = ?', $permission->permission_id)
		->execute();
	}
    }

    public function clearPermissionsForRole($pType, $pRole){
	$type_id = $this->getModelObjectId($pType);
	$resource = "type.{$type_id}";

	$Roles = new Silk_Roles();
	$role_id = $Roles->getModelObjectId($pRole);

	$Permissions = new Silk_Permissions();
	$permissions = $Permissions->fetchByResource($resource);

	foreach ($permissions as $permission){
// 	    logdebug('Objects.clearPermissionsForRole: Clearing permissions on ' . $permission->resource . ' for role ' . $role_id);
	    Doctrine_Query::create()
		->delete('Silk_Dao_RolePermission rp')
		->where('rp.role_id = ?', $role_id)
		->andWhere('rp.permission_id = ?', $permission->permission_id)
		->execute();
	}
    }


    public function setPermissions($pType, array $pRolePermissions, array $pUserPermissions){
	$type = $this->getModelObject($pType);

	$resource = "type.{$type->type_id}";

	$Permissions = new Silk_Permissions();
	$Roles = new Silk_Roles();
	$Users = new Silk_Users();

	if (count($pRolePermissions) > 0){
	    logdebug("Silk_Types.setPermissions: Setting permissions for type [$type->type_id]");
	    $roles = $pRolePermissions['role'];
	    if (array_key_exists('privilege', $pRolePermissions)){
		$privileges = $pRolePermissions['privilege'];

		foreach ($roles as $i => $role_id){
		    logdebug("Silk_Types.setPermissions: Setting permissions for type [$type->type_id] and role [$role_id]");
		    $this->clearPermissionsForRole($type, $role_id);

		    $role_privileges = $privileges[$role_id];

		    foreach ($role_privileges as $privilege){
			$permission = $Permissions->fetchByResourceAndPrivilege($resource, $privilege);
			if (!$permission)
			    $permission = $Permissions->create(array(
				'resource' => $resource,
				'privilege' => $privilege,
				'name' => "Type {$type->type_id} " . ucfirst($privilege)
			    ), true);

// 			if ($permission){
			    logdebug("Types.setPermission: Assigning permission {$permission->resource}.{$permission->privilege} to role {$role_id}");
			    $rp = new Silk_Dao_RolePermission();
			    $rp->role_id = $role_id;
			    $rp->permission_id = $permission->permission_id;
			    $rp->save();
// 			} else
// 			    logwarn("Attempting to assign an invalid permission {$resource}:{$privilege} to role {$role_id}");
		    }
		}
	    }
	}

	if (count($pUserPermissions) > 0){
	    $users = $pUserPermissions['user'];
	    if (array_key_exists('privilege', $pUserPermissions)){
		$privileges = $pUserPermissions['privilege'];

		foreach ($users as $i => $user_id){

		    $this->clearPermissionsForUser($type, $user_id);

		    $user_privileges = $priviliges[$user_id];

		    foreach ($user_privilges as $privilege){
			$permission = $Permissions->fetchByResourceAndPrivilege($resource, $privilege);
			if (!$permission)
			    $permission = $Permissions->create(array(
				'resource' => $resource,
				'privilege' => $privilege,
				'name' => "Type {$type->type_id} " . ucfirst($privilege)
			    ), true);
// 			if ($permission){
			    $rp = new Silk_Dao_UserPermission();
			    $rp->user_id = $user_id;
			    $rp->permission_id = $permission->permission_id;
			    $rp->save();
// 			} else
// 			    logwarn("Attempting to assign an invalid permission {$resource}:{$privilege} to user {$user_id}");
		    }

		}
	    }
	}
    }

    public function render($pType, Silk_Object $pObject=null, $pAction=null, array $pVars=array()){
 	$type = $this->getModelObject($pType);
	$ModuleType = $this->getModuleType($type);

	if ($ModuleType){
	    $template = $type->getTemplate($pAction);
	    if ($template)
		return $ModuleType->render($pObject, $template, $pVars);
	    else if ($pAction)
		return $ModuleType->render($pObject, $pAction, $pVars);
	    else
		return $ModuleType->render($pObject, null, $pVars);
	} else
	    throw new Silk_Exception('This type is no longer available - ' . $type->slug);

    }

    public function instantiate($pType, array $pData, $pAutoSave=false){

// 	logdebug("Silk_Types.instantiate: Fetching type {$pType}");

	$type = $this->getModelObject($pType);

	Silk::debug('Silk_Types.instantiate: Instantiating ' . $type->name);

	if (Silk::HasPermission(array('resource' => "type.{$type->type_id}", 'privilege' => PERMISSION_CREATE))){

	    $site = Silk::GetCurrentSite();
	    $identity = Silk::GetIdentity();

	    $data = array();
	    $data['type_id'] = $type->type_id;
	    $data['site_id'] = $site->site_id;

	    if ($identity)
		$data['user_id'] = $identity->user_id;

	    $Objects = new Silk_Objects();

	    $object = $Objects->create(array_merge(
		$pData,
		$data
	    ), $pAutoSave);

	    return $object;
	} else
	    throw new Silk_Acl_Exception('Insufficient privileges to create type - ' . $type->name, Silk_Acl_Exception::ACCESS_DENIED);
    }

    public function getModuleType($pType){
	$type = $this->getModelObject($pType);
	if ($type->virtual)
	    $ModuleType = Silk::getVirtualTypeDefinition($type);
	else
	    $ModuleType = Silk::getTypeDefinition($type->slug);

	return $ModuleType;
    }

    public function getTemplate($pType, $pAction){

// 	logdebug("Silk_Types.getTemplate: Getting id for type " . logobject($pType));
	$type_id = $this->getModelObjectId($pType);

	$Templates = new Silk_Templates();
	return $Templates->getTemplateForTypeByName($type_id, $pAction);
    }

    public function getTemplates($pType){
	$type_id = $this->getModelObjectId($pType);

	$Templates = new Silk_Templates();
	return $Templates->getTemplatesForType($type_id);
    }

    public function getTypeMetas($pType){
	$type_id = $this->getModelObjectId($pType);

	$Metas = new Silk_TypeMetas();
	return $Metas->getTypeMetasForType($type_id);
    }

    public function getObjects($pType)
    {
        $type_id = $this->getModelObjectId($pType);

        $Objects = new Silk_Objects();

        return $Objects->getObjectsForType($type_id);
    }

    public function getSites($pObjectType)
    {
        $object_type_id = $this->getModelObjectId($pObjectType);

        $Sites = new Silk_Sites();

        return $Sites->getSitesForType($object_type_id);
    }

    public function getVersionForType($pTypeName){

	$results = $this->fetchByName($pTypeName);

	if (count($results) > 0){

	    $type = $results->current();
	    return $type->version;
	}
	return false;
    }

    public function getPermissions($pType){
	$type_id = $this->getModelObjectId($pType);
	$resource = "type.{$type_id}";
	$Permissions = new Silk_Permissions();
	return $Permissions->fetchByResource($resource);
    }


    public function clearTemplates($pType){
	$templates = $this->getTemplates($pType);

	foreach ($templates as $action)
	    $action->delete();

    }

    public function clearMetas($pType){
	$metas = $this->getTypeMetas($pType);

	foreach ($metas as $meta)
	    $meta->delete();
    }

    public function getTemplateCollection(array $pTemplates){
	$Templates = new Silk_Templates();
	return $Templates->getModelCollection($pTemplates);
    }

    public function getMetaCollection(array $pMetas){
	$TypeMetas = new Silk_TypeMetas();
	return $TypeMetas->getModelCollection($pMetas);
    }

    public function getModelObject($pType){
	if (is_string($pType) && !is_numeric($pType))
	    return $this->fetchBySlug($pType, true);
	else
	    return parent::getModelObject($pType);
    }

    public function getModelObjectId($pType){
	if (is_string($pType) && !is_numeric($pType)){
	    logdebug("Types.getModelObjectId: Fetching type with name {$pType}");
	    $type = $this->fetchBySlug($pType, true);
	    logdebug("Types.getModelObjectId: Got type {$type->type_id}");
	    return $type->type_id;
	} else
	    return parent::getModelObjectId($pType);
    }
}

 ?>